#pragma once

#include <thread>
#include <functional>
#include <vector>
#include <mutex>
#include <sys/eventfd.h>
#include <unistd.h>
#include <memory>
#include "Log.hpp"

#include "Channel.hpp"
#include "Timerwheel.hpp"

class Channel;

// Eventloop用于epoll的监控的事件,就绪后的(线程\描述符)分配
// 以线程为基本单位使用（减少锁的使用）
class EventLoop
{
private:
    using Functor = std::function<void()>;
    // 用于隔离去执行不同的fd事件的线程（单个线程只负责指定的fd就绪事件的回调函数），减少锁的使用，只用锁单个fd的执行流，而不是锁所有
    std::thread::id _threadId;              // 线程id
    int _eventFd;                           // 唤醒事件监控导致的阻塞
    std::unique_ptr<Channel> _eventChannel; // eventfd响应事件管理
    Poller _poller;                         // 事件监控模块
    std::vector<Functor> _tasks;            // 当前就绪的任务池
    std::mutex _mutex;                      // 用于任务池线程安全的锁
    TimerWheel _timerWhell;                 // 定时器模块

    // eventfd相关
public:

    // 创建eventfd
    int CreatEventFd()
    {
        // 禁止进程复制(子进程继承)  |   非阻塞
        int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (efd < 0)
        {
            ELOG("CREATE EVENTFD FAILED!!");
            abort();
        }
        return efd;
    }

    void ReadEventFd()
    {
        uint64_t res = 0;
        int ret = read(_eventFd, &res, sizeof(res));
        if (ret < 0)
        {
            // 信号中断或无数据可读
            if (errno == EINTR || errno == EAGAIN)
                return;

            ELOG("READ EVENTFD FAILED");
            abort();
        }

        return;
    }

    // 唤醒eventfd,本质就是给它写入即可
    void WakeUpEventFd()
    {
        uint64_t val = 1;
        int ret = write(_eventFd, &val, sizeof(val));
        if (ret < 0)
        {
            if (errno == EINTR)
            {
                return;
            }
            ELOG("READ EVENTFD FAILED!");
            abort();
        }
        return;
    }

public:
    // 执行所有任务池的任务
    void RunAllTask()
    {
        std::vector<Functor> functor;
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.swap(functor);
        }
        for (auto &f : functor)
            f();

        return;
    }

public:
    EventLoop() : _threadId(std::this_thread::get_id()),
                  _eventFd(CreatEventFd()),
                  _eventChannel(new Channel(this, _eventFd)),
                  _timerWhell(this)

    {
        // 给eventfd添加可读事件回调函数，读取eventfd事件通知次数
        _eventChannel->SetReadCallback(std::bind(&EventLoop::ReadEventFd, this));
        // 启动eventfd的读事件监控
        _eventChannel->EnableRead();
    }

    // 将任务压入任务池
    void QueueInLoop(const Functor &cb)
    {
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _tasks.push_back(cb);
        }
        // 通过eventfd通知（有可能由于eventfd由于之前没有可读，epoll被阻塞了）
        WakeUpEventFd();
    }

    // 判断当前EventLoop是否属于当前线程
    bool IsInLoop()
    {
        return _threadId == std::this_thread::get_id();
    }

    // 某项任务必须在该线程进行，调用都会有问题
    void AssertInLoop()
    {
        assert(_threadId == std::this_thread::get_id());
    }

    // 执行任务，若当前任务不在线程内，则压入任务队列，若在则直接直接执行
    void RunInLoop(const Functor &cb)
    {
        if (IsInLoop())
            return cb();
        return QueueInLoop(cb);
    }

    // 修改/添加描述符的事件监控
    void UpdateEvent(Channel *Channel) { return _poller.UpdateEvent(Channel); }

    // 移除描述符监控
    void RemoveEvent(Channel *Channel) { return _poller.RemoveEvent(Channel); }

    // 启动（1、通过epoll获取就绪事件 2、就绪事件处理 3、执行其它任务，及需要借用loop模块达到单线程的任务执行解决线程安全）
    void Start()
    {
        while (1)
        {
            // 1. 事件监控，
            std::vector<Channel *> actives;
            _poller.Poll(&actives);
            // 2. 事件处理。
            for (auto &channel : actives)
            {
                channel->HandleEvent();
            }
            // 3. 执行任务
            RunAllTask();
        }
    }

    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb) { return _timerWhell.TimerAdd(id, delay, cb); }
    void TimerRefresh(uint64_t id) { return _timerWhell.TimerRefresh(id); }
    void TimerCancel(uint64_t id) { return _timerWhell.TimerCancel(id); }
    bool HasTimer(uint64_t id) { return _timerWhell.HasTimer(id); }
};

void Channel::Remove() { _loop->RemoveEvent(this); }
void Channel::Update() { _loop->UpdateEvent(this); }

// 定时任务添加
void TimerWheel::TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop, this, id, delay, cb));
}
// 刷新/延迟定时任务
void TimerWheel::TimerRefresh(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshInLoop, this, id));
}
// 定时任务取消
void TimerWheel::TimerCancel(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerCancelInLoop, this, id));
}

